# Genera un archivo bin y un archivo txt a partir del zxb y de los parametros que se ingresan. Luego los copia 
# a projecto/binarios  al bin y a projectos/binarios/txts  el txt
# el offset x al final no lo uso porque si tengo que imprimir la parte del sprite de arriba en un offset y luego el mismo sprite en otro 
# desperdicio memoria, asi que lo manejo directamente desde boriel
import sys
import os

def cargar_datos():
    # Verificar que al menos se pasó el nombre del archivo y una cantidad válida de números
    if len(sys.argv) < 8:  # 1 para el script,1 para el offset x, 1 para la direccion, 1 para el archivo y mínimo 4 números
        print("Uso: python script.py <archivo> num1 num2 num3 num4 ...")
        sys.exit(1)

    offset   =  sys.argv[1]
    direccion = sys.argv[2]

    # Extraer el path del archivo (primer argumento)
    archivo_path = sys.argv[3]
    
    # Leer los números restantes desde la línea de comandos y convertirlos a enteros
    args = list(map(int, sys.argv[4:]))

    # Verificar que la cantidad de números sea múltiplo de 4
    if len(args) % 4 != 0:
        print("Error: La cantidad de números debe ser múltiplo de 4")
        sys.exit(1)

    # Crear la tupla de tuplas
    tupla = tuple(tuple(args[i:i+4]) for i in range(0, len(args), 4))

    return offset,direccion,archivo_path, tupla


def procesar_archivo(offset,direccion,nombre_archivo,datos): 
    with open(nombre_archivo, 'r', encoding='utf-8') as archivo:

        nroLinea = 0
        listaSprite = []
        listaAtributosSprite = []
        listaSpriteConvertida = []
        atributos =0

        for linea in archivo:
            nroLinea += 1
            
            if nroLinea == 1: 
                mensajeCorrecto =  linea.strip()
                if not mensajeCorrecto.startswith("ZX-Paintbrush image"):
                    print("El archivo ingresado por línea de comandos no es válido.")
                    sys.exit(1)

            if nroLinea < 3:
                continue

            linea = linea.strip()
            if linea == "":  # Línea vacía indica el fin
                atributos =1
                continue

            # Si atributos = 0 entonces:
            # Convierte la cadena de bit en bytes y guarda esos bytes en una lista de listas. Donde el contenido de cada lista exterior 
            # representa una linea de pixeles del grafico. Cada dato de la linea interior representa 8 posiciones(pixeles) de la linea. 
            # Si atributos =1 significa que en el escaneo del archivo ya paso de la zona de pixeles y que ahora la informacion de archivo 
            # son atributos entonces:
            # Cada dato ahora representa losa atributos de 64 bits, un caracter. Por lo que ahora cada lista exterior  representa los atributos 
            # de una linea de caracteres. Y cada dato de esa lista el atributo de un caracter particular.
            # Los datos estan representados de izquierda a derecha y de ahi abajo y se repite el ciclo
            if atributos ==0: #Si esta variable es 0 significa que se estan volcando los datos de tinta
                filaTinta = []         #crea una lista  para guardar una fila de datos tinta
                for i in range(0, len(linea), 8):
                    byte_str = linea[i:i+8]
                    if len(byte_str) == 8:
                        filaTinta.append(int(byte_str, 2))
                listaSprite.append(filaTinta)
            else:     #Si esta variable es 1 signica que se estan volcando los datos de atributos
                filaAtributos = []
                for hex_val in linea.split():                      
                        filaAtributos.append(int(hex_val, 16))
                listaAtributosSprite.append(filaAtributos)    

        
        subListaAtributos = []

        for linea in datos:
            columCaracterDesde = linea[0]  #columCaracterDesde = datos[0][0]
            columCaracterHasta = linea[1]
            filaCaracterDesde = linea[2]
            filaCaracterHasta = linea[3]
            filaLineaCaracterDesde = filaCaracterDesde*8
            filaLineaCaracterHasta = filaCaracterHasta*8 +7
            filaPixeles =filaLineaCaracterDesde-1
            filaAtributos = filaCaracterDesde-1
            subListaSprite = []
            lineasASaltar = filaLineaCaracterDesde
            caracteresASaltar =  filaCaracterDesde

            for listaFila in listaSprite[lineasASaltar:]: # for listaFila in listaSprite:
                    filaPixeles = filaPixeles +1
                    if (filaPixeles >= filaLineaCaracterDesde and filaPixeles <= filaLineaCaracterHasta):
                        nuevaFila = []
                        for n in range(columCaracterDesde,columCaracterHasta +1):
                            nuevaFila.append(listaFila[n])
                        subListaSprite.append(nuevaFila)

            for listaFila in listaAtributosSprite[caracteresASaltar:]:
                    filaAtributos = filaAtributos + 1
                    if (filaAtributos  >= filaCaracterDesde  and filaAtributos <= filaCaracterHasta):
                        nuevaFila = []
                        for n in range(columCaracterDesde,columCaracterHasta+1):
                            nuevaFila.append(listaFila[n])
                        subListaAtributos.append(nuevaFila)   


            # Procesar la lista de listas listaSprite (tinta) para ordenarla para zx basic printcharts
            caracter = []
            i = 0
            for n in range(0, len(subListaSprite[0])):
                for fila in subListaSprite:
                    caracter.append(fila[n])
                    i += 1
                    if i == 8:
                        i = 0
                        listaSpriteConvertida.append(caracter)
                        caracter = []



    # Preparar el nombre base y el archivo de salida (.bas)
    base = os.path.splitext(os.path.basename(nombre_archivo))[0]  # nombre sin extensión
    # Se asume que cada sublista en sprite tiene 8 datos, por lo que:
    total_datos = len(listaSpriteConvertida) * 8
    # Construir el nombre del archivo de salida
    nombre_salida = os.path.join(os.path.dirname(nombre_archivo), base + ".bas")

    with open(nombre_salida, 'w', encoding='utf-8') as salida:
        # Escribir la primera línea:
        # La cantidad de datos es total_datos - 1 según lo solicitado.
        salida.write(f'DIM {base}({total_datos}) AS UByte => {{ _\n')
        
        # Escribir cada fila de datos (8 valores en hexadecimal con $)
        for idx, fila in enumerate(listaSpriteConvertida):
            # Convertir cada dato a hexadecimal de dos dígitos con $ adelante.
            hex_datos = [f"${dato:02X}" for dato in fila]
            # Unir los datos separados por coma y un espacio.
            linea = ', '.join(hex_datos)
            # Para cada fila se agrega al final: si no es la última, se pone coma y luego " _"
            # Si es la última, se omite la coma final, pero se agrega el " _"
            if idx != len(listaSpriteConvertida) - 1:
                salida.write(linea + ', _\n')
            else:
                salida.write(linea + ' _\n')
        # Línea final con la llave de cierre.
        salida.write('}\n')

        total_datos = sum(len(sublista) for sublista in subListaAtributos) #permite obtener la cant. total de elementos pese a que cada sublista tiene distinta cant de elementos
        salida.write(f'DIM {base}_Attr({total_datos}) AS UByte => {{ _\n')
        # Escribir cada fila de datos (8 valores en hexadecimal con $)
        for idx, fila in enumerate(subListaAtributos):
            # Convertir cada dato a hexadecimal de dos dígitos con $ adelante.
            hex_datos = [f"${dato:02X}" for dato in fila]
            # Unir los datos separados por coma y un espacio.
            linea = ', '.join(hex_datos)
            # Para cada fila se agrega al final: si no es la última, se pone coma y luego " _"
            # Si es la última, se omite la coma final, pero se agrega el " _"
            if idx != len(subListaAtributos) - 1:
                salida.write(linea + ', _\n')
            else:
                salida.write(linea + ' _\n')
        # Línea final con la llave de cierre.
        salida.write('}\n\n\n')

        indicePutChars = 0
        indicePaintData = 0
        salida.write(f"/'")
        for linea in datos:
            columCaracterDesde = linea[0]  #columCaracterDesde = datos[0][0]
            columCaracterHasta = linea[1]
            filaCaracterDesde = linea[2]
            filaCaracterHasta = linea[3]
            
            #salida.write(f"\nputChars(x+{columCaracterDesde},y+{filaCaracterDesde} ,{columCaracterHasta - columCaracterDesde + 1},"
            #f"{filaCaracterHasta - filaCaracterDesde + 1},@{base}+{indicePutChars})\n")
            #salida.write(f"PaintData(x+{columCaracterDesde},y+{filaCaracterDesde} ,{columCaracterHasta - columCaracterDesde + 1},"
            #f"{filaCaracterHasta - filaCaracterDesde + 1},@{base}_Attr+{indicePaintData})\n")
            salida.write(f"\nimprimoLineaSprite(x+oS+{columCaracterDesde},y+{filaCaracterDesde} ,{columCaracterHasta - columCaracterDesde + 1},"
            f"@{base}+{indicePutChars},@{base}_Attr+{indicePaintData})")    
            indicePutChars = indicePutChars + ((columCaracterHasta - columCaracterDesde +1) * (filaCaracterHasta- filaCaracterDesde+1)*8)
            indicePaintData = indicePaintData + ((columCaracterHasta - columCaracterDesde +1) * (filaCaracterHasta- filaCaracterDesde+1))
        #****************************************************************************************
        # informacion de los puntos a reimprimir el background
        #******************************************************************************************
        # for linea in datos:
        #     columCaracterDesde = linea[0]  #columCaracterDesde = datos[0][0]
        #     columCaracterHasta = linea[1]
        #     filaCaracterDesde = linea[2]
        #     filaCaracterHasta = linea[3]

        #     offset = columCaracterDesde - 1
        #     signo = "+" if offset >= 0 else "-"
        #     valor = abs(offset)

        #     if direccion == "r":
        #         salida.write(f"\nimprimoCaracterMapa(x+oS{signo} {valor} ,y+{filaCaracterDesde})")
        #     elif direccion == "l":
        #         salida.write(f"\nimprimoCaracterMapa(x+oS+{(columCaracterHasta - columCaracterDesde + 1)+columCaracterDesde} ,y+{filaCaracterDesde})")
            
                
        # salida.write(f"\n'/")

    #******************************************************************************
    #  Crear el archivo .bin con los datos en el mismo orden que en el archivo .bas
    #*******************************************************************************
    nombre_bin = os.path.join(os.path.dirname(nombre_archivo), base + ".bin")
    contadorBytes = 0
    inicioAtributos = 0
    inicioPosicional = 0
    longitudPosicional =0
    with open(nombre_bin, 'wb') as binario:
        # Guardar primero los datos de tinta (listaSpriteConvertida)
        for fila in listaSpriteConvertida:
            for byte in fila:
                binario.write(bytes([byte]))
                contadorBytes = contadorBytes +1
        inicioAtributos = contadorBytes
        longitudSprites =  contadorBytes


        # Luego guardar los datos de atributos (subListaAtributos)
        for fila in subListaAtributos:
            for byte in fila:
                binario.write(bytes([byte]))
                contadorBytes = contadorBytes +1
        inicioPosicional = contadorBytes
        longitudAtributos = contadorBytes -longitudSprites

        #guardar datos posicionales de cada linea de sprites
        indicePaintData = 0
        for linea in datos:
            columCaracterDesde = linea[0]  #columCaracterDesde = datos[0][0]
            columCaracterHasta = linea[1]
            filaCaracterDesde = linea[2]
            filaCaracterHasta = linea[3]

            valor = int(columCaracterDesde) + int(offset)
            binario.write(bytes([valor]))
            #binario.write(bytes([columCaracterDesde]+ offset))
            binario.write(bytes([columCaracterHasta - columCaracterDesde + 1]))
            binario.write(bytes([indicePaintData]))
            indicePaintData = indicePaintData + ((columCaracterHasta - columCaracterDesde +1) * (filaCaracterHasta- filaCaracterDesde+1))
            longitudPosicional = longitudPosicional +3


    print(f"Archivo binario guardado en: {nombre_bin}")

    #******************************************************************************
    #  Crear el archivo .txt con los datos especificados
    #*******************************************************************************
    nombre_txt = os.path.join(os.path.dirname(nombre_archivo), base + ".txt")
    with open(nombre_txt, 'w', encoding='utf-8') as archivoTxt:
        archivoTxt.write("1".ljust(24) + "SPRITE FILE\n")
        archivoTxt.write(f"{str(0).ljust(8)}{str(longitudSprites).ljust(8)}{base}_s\n")
        archivoTxt.write(f"{str(inicioAtributos).ljust(8)}{str(longitudAtributos).ljust(8)}{base}_a\n")
        archivoTxt.write(f"{str(inicioPosicional).ljust(8)}{str(longitudPosicional).ljust(8)}{base}_p\n")
        

    print(f"***CONVERSION ARCHIVO ZX PAINTBRUSH . ZXP A BAS ENTENDIBLE PARA PUTCHART")
    print(f"Archivo procesado y guardado en: {nombre_salida}")
    #input("Presiona Enter para salir...")



offset,direccion,nombre_archivo, datos = cargar_datos()
print(f"Archivo a procesar: {nombre_archivo}")
print(f"Datos: {datos}")


procesar_archivo(offset,direccion,nombre_archivo,datos)
